﻿/**
 * Author: Rick van Rijn(RVR), Dennis van der Werf(DVW)
 * Date: 26-3-2012
 * Groep: 3
 * Versiebeheer:
 * Version 1.0 Algorithm created RVR
 * Version 1.1 Little bug fixed RVR
 * Version 1.2 Lookup tables implemented DVW
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;

namespace KentekenHerkenning
{
    class EqualisationAlgorithm
    {

        public static Bitmap DoAlgorithm(System.Drawing.Bitmap sourceImage)
        {
            //copy Bitmap and lockbits for alternation
            Bitmap renderedImage = new Bitmap(sourceImage);
            Rectangle rect = new Rectangle(0, 0, renderedImage.Width, renderedImage.Height);
            BitmapData returnImageDate = renderedImage.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

            //create safe pointer
            IntPtr pointer = returnImageDate.Scan0;
            int Size = Math.Abs(returnImageDate.Stride) * renderedImage.Height;

            //arrays of Byte type for BitmapData
            byte[] invert = new Byte[Size];
            byte[] temp = new Byte[Size];

            //copy pointer data to byte array:: invert
            System.Runtime.InteropServices.Marshal.Copy(pointer, invert, 0, Size);

            //get total of pixels and calculate the const value
            uint pixels = (uint)renderedImage.Height * (uint)renderedImage.Width;
            decimal Const = 255 / (decimal)pixels;

            //Create histogram arrays for R,G,B channels
            int[] cdfR = new int[256];
            int[] cdfG = new int[256];
            int[] cdfB = new int[256];
            for (int i = 0; i < Size; i += 4)
            {
                cdfR[invert[i + 2]]++;
                cdfG[invert[i + 1]]++;
                cdfB[invert[i]]++;
            }

            //Convert arrays to cumulative distribution frequency data
            for (int r = 1; r <= 255; r++)
            {
                cdfR[r] = cdfR[r] + cdfR[r - 1];
                cdfG[r] = cdfG[r] + cdfG[r - 1];
                cdfB[r] = cdfB[r] + cdfB[r - 1];
            }

            //create lookup table 
            byte[] lutR = new Byte[256];
            byte[] lutG = new Byte[256];
            byte[] lutB = new Byte[256];
           
            for (int i = 0; i <= 255; i++)
            {
                lutR[i] = (byte)((decimal)cdfR[i] * Const);
                lutG[i] = (byte)((decimal)cdfG[i] * Const);
                lutB[i] = (byte)((decimal)cdfB[i] * Const);
            }

            //Calculate new values and store in temp array
            for (int i = 0; i < Size; i += 4)
            {
                temp[i] = lutB[invert[i]];//B
                temp[i + 1] = lutG[invert[i + 1]];//G
                temp[i + 2] = lutR[invert[i + 2]];//R
            }

            //copy temp array to invert array
            for (int i = 0; i < Size; i += 4)
            {
                invert[i] = temp[i];
                invert[i + 1] = temp[i + 1];
                invert[i + 2] = temp[i + 2];
            }

            //copy invert array to BitmapData
            System.Runtime.InteropServices.Marshal.Copy(invert, 0, pointer, Size);

            //unlock Bitmap
            renderedImage.UnlockBits(returnImageDate);

            //Return Bitmap
            return renderedImage;
        }
    }
}
